package com.banggood.upms.common.util;


import org.springframework.util.StringUtils;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

/**
 * 此工具类主要是针对公司 .net 的 AES 加密，常规 Java 的 AES 加密不要使用该方式
 *
 * @author zch，2017-05-09
 */
public final class AESHelper {

    /**
     * AES 编码
     *
     * @param context 被编码字符串
     * @param key     密钥
     * @return
     */
    public static String encrypt(String context, String key) {
        if (StringUtils.isEmpty(context)) {
            return null;
        }
        try {
            //这里使用 UTF-16LE 是因为 .net 那边使用的是：Encoding.Unicode.GetBytes(aesKey)
            byte[] raw = key.getBytes(StandardCharsets.UTF_16LE);
            byte[] md5Bytes = md5Java(raw);
            SecretKeySpec secretKeySpec = new SecretKeySpec(md5Bytes, "AES");
            //使用CBC模式，需要一个向量iv，可增加加密算法的强度。其中：new byte[16] 在 .net 中是计算出来的，这里直接用计算后的结果
            IvParameterSpec iv = new IvParameterSpec(new byte[16]);
            //"算法/模式/补码方式"
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, iv);
            //这里使用 UTF-16LE 是因为 .net 那边使用的是：Encoding.Unicode.GetBytes(aesKey)
            byte[] encrypted = cipher.doFinal(context.getBytes(StandardCharsets.UTF_16LE));
            //此处使用BASE64做转码。
            return Base64.getEncoder().encodeToString(encrypted);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * AES 解码
     *
     * @param context 被解密字符串
     * @param key     密钥
     * @return
     */
    public static String decrypt(String context, String key) {
        if (StringUtils.isEmpty(context)) {
            return null;
        }
        try {
            //这里使用 UTF-16LE 是因为 .net 那边使用的是：Encoding.Unicode.GetBytes(aesKey)
            byte[] raw = key.getBytes(StandardCharsets.UTF_16LE);
            SecretKeySpec secretKeySpec = new SecretKeySpec(md5Java(raw), "AES");
            IvParameterSpec iv = new IvParameterSpec(new byte[16]);
            //"算法/模式/补码方式"
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, iv);

            Base64.Decoder decoder = Base64.getDecoder();
            byte[] decode = decoder.decode(context);

            //对 base64 解码后的内容进行 AES 解码
            byte[] original = cipher.doFinal(decode);
            String originalString = new String(original, StandardCharsets.UTF_16LE);
            return originalString;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * MD5 哈希
     *
     * @param message
     * @return
     */
    private static byte[] md5Java(byte[] message) {
        if (null == message) {
            return null;
        }
        MessageDigest md = null;
        try {
            md = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return md.digest(message);
    }
}
